﻿#pragma once
#include <queue>

using namespace std;

#define BLKSIZE 1024*1024*2

const unsigned char packet_start_code_prefix[3] = { 0x00, 0x00, 0x01 };
const unsigned char end_code[4] = { 0x00, 0x00, 0x01, 0xb9 };
const unsigned char pack_start_code_byte[4] = { 0x00, 0x00, 0x01, 0xba };
const unsigned char system_header_start_code[4] = { 0x00, 0x00, 0x01, 0xbb };
const unsigned char audio_pack_start_code[4] = { 0x00, 0x00, 0x01, 0xc0 };
const unsigned char video_pack_start_code[4] = { 0x00, 0x00, 0x01, 0xe0 };
const unsigned char H264_nalu_start_code[4] = { 0x00, 0x00, 0x00, 0x01 };

struct DataInfo
{
	char* puBuf;
	int iSize;

	DataInfo()
	{
		puBuf = NULL;
		iSize = 0;
	}
};

//Pack structure
struct ps_pack{
	LONGLONG scr;		//system_clock_reference_base
	short scre;			//system_clock_reference_extension
	int rate;			//program_mux_rate
	short stufflength;	//pack_stuffing_length
};
//
//union littel_endian_size
//{
//	unsigned short int  length;
//	unsigned char       byte[2];
//};
//
//struct stu_pack_start_code
//{
//	unsigned char start_code[3];
//	unsigned char stream_id[1];
//};
//
//struct program_stream_e
//{
//	stu_pack_start_code     PackStart;
//	littel_endian_size  PackLength;//we mast do exchange  
//	char                PackInfo1[2];
//	unsigned char       stuffing_length;
//};

class TransVideo
{
public:
	TransVideo();
	~TransVideo();

	void pushDataToQueue(DataInfo dataInfo){ //使用临界区加锁
		m_dq_buf.push(dataInfo);
	}

	CRITICAL_SECTION m_lock;

	void transVideoStart();
	static DWORD WINAPI thread_work(LPVOID lpParmeter);
	void setTransVideoStop(bool videoStop){ stop_trans = videoStop; }

private:
	HANDLE out_hFile;
	HANDLE out_mFile;

	HANDLE out_auFile;
	HANDLE out_aFile;

	queue<DataInfo> m_dq_buf;


	DWORD ThreadId;
	char *out_fn = "video.h264";
	char *mpeg_fn = "video.mpeg";

	char* aac_fn = "audio.wav";
	char* audio_fn = "audio.ps";

	bool stop_trans = false;
	unsigned char h264_buf[BLKSIZE];
	unsigned char aac_buf[BLKSIZE];

	unsigned char market_buf[4];

	unsigned char *offset = market_buf;

	unsigned char* h264_pack = h264_buf;
	unsigned char* aac_pack = aac_buf;

	bool first_byte = true;
	bool IsFirstPack = true;
	int pes_length = 0;
	int aac_length = 0;

	int pack_num;
	char LastH264FrameNaluHeader[5];

	void parse_pack(HANDLE out_hFile);
	void fatal(int ret, char *format, ...);
	LONGLONG parse_muxrate(unsigned char *p);
	LONGLONG parse_scr(unsigned char *p);
};

inline void TransVideo::fatal(int ret, char *format, ...)
{


	fprintf(stderr, "fatal error");
	if (format)
	{
		fprintf(stderr, ": ");
		if (ret >= 2) fprintf(stderr, "pack num %d: ", pack_num);
	}
	else
		fprintf(stderr, "\n");

	exit(ret);
}

inline LONGLONG TransVideo::parse_scr(unsigned char *p)
{
	int tmp;
	LONGLONG ltmp;

	tmp = *p++;
	if (((tmp >> 6) & 3) != 1)
		fatal(2, "This file is not a MPEG2 file!\n");
	//get scr and scr ext;
	ltmp = tmp & 0x38;
	ltmp = ltmp << 27;
	tmp <<= 8;
	tmp += *(p++);
	ltmp += (tmp & 0x03ff) << 20;
	tmp = *(p++);
	ltmp += (tmp & 0xf8) << 12;
	tmp <<= 8;
	tmp += *(p++);
	ltmp += (tmp & 0x03ff) << 5;
	tmp = *(p++);
	ltmp += (tmp & 0xf8) >> 3;
	tmp <<= 8;
	tmp += *(p++);
	ltmp <<= 9;
	ltmp += (tmp & 0x3fe) >> 1;

	return (ltmp);
}

inline LONGLONG TransVideo::parse_muxrate(unsigned char *p)
{
	int tmp;
	LONGLONG ltmp;

	tmp = *p++;
	tmp <<= 8;
	tmp += *(p++);
	tmp <<= 8;
	tmp += *(p++);
	ltmp = (tmp & 0xfffffc) >> 1;
	return (ltmp);
}